<?php
/**
 *+------------------
 * Lflow
 *+------------------
 * Copyright (c) 2023~2030 gitee.com/liu_guan_qing All rights reserved.本版权不可删除，侵权必究
 *+------------------
 * Author: Mr.April(405784684@qq.com)
 *+------------------
 */
declare (strict_types=1);

namespace lflow\parser;

use lflow\model\NodeModel;
use lflow\model\ProcessModel;
use lflow\WorkFlowException;

/**
 * 流程定义json解析并将解析后对象放入模型容器中
 *
 * @author Mr.April
 * @since  1.0
 */
class ModelParser
{

    /**
     * 解析流程定义文件，并将解析后的对象放入模型容器中
     *
     * @param object $workflow
     *
     * @return \lflow\model\ProcessModel
     * @throws \lflow\WorkFlowException
     */
    public static function parse(object $workflow): ProcessModel
    {
        $workflow = json_decode($workflow->getContent());
        if (empty($workflow)) {
            throw new WorkFlowException("流程定义 is null");
        }
        try {
            $process = new ProcessModel();
            $process->setName($workflow->{NodeParser::ATTR_NAME} ?? '');
            $process->setDisplayName($workflow->{NodeParser::ATTR_DISPLAYNAME} ?? '');
            $process->setExpireTime($workflow->{NodeParser::ATTR_EXPIRETIME} ?? '');
            $process->setInstanceUrl($workflow->{NodeParser::ATTR_INSTANCEURL} ?? '');
            $process->setInstanceNoClass($workflow->{NodeParser::ATTR_INSTANCENOCLASS} ?? '');
            $nodeList = $workflow->nodes ?? (object)[];
            foreach ($nodeList as $rows) {
                $model   = self::parseModel($workflow, $rows);
                $array   = $process->getNodes();
                $array[] = $model;
                $process->setNodes($array);
            }

            //循环节点模型，构造变迁输入、输出的source、target
            foreach ($process->getNodes() as $node) {
                foreach ($node->getOutputs() as $transition) {
                    $to = $transition->getTo();
                    foreach ($process->getNodes() as $node2) {
                        if ($to === $node2->getName()) {
                            $inputs   = $node2->getInputs();
                            $inputs[] = $transition;
                            $node2->setInputs($inputs);
                            $transition->setTarget($node2);
                        }
                    }
                }
            }
            return $process;
        } catch (\Exception|\Error $e) {
            throw new WorkFlowException($e);
        }
    }

    /**
     * 对流程定义json的节点，根据其节点对应的解析器解析节点内容
     *
     * @param object $workflow
     * @param object $node
     *
     * @return \lflow\model\NodeModel
     * @throws \lflow\WorkFlowException
     */
    private static function parseModel(object $workflow, object $node): NodeModel
    {
        try {
            //\\解决兼容windows&linux 运行
            $parser     = "\\lflow\\parser\\ipml\\" . ucfirst($node->type) . 'Parser';
            $nodeParser = new $parser();
            $nodeParser->parse($workflow, $node);
            return $nodeParser->getModel();
        } catch (\Exception $e) {
            throw new WorkFlowException($e);
        }
    }
}
